package edu.hawaii.duedates.lender;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotSame;
import static org.junit.Assert.assertTrue;
import org.junit.Test;

import java.util.Calendar;
import java.util.Date;
import java.util.Locale;
import java.text.SimpleDateFormat;

/**
 * Implements testing of the BorrowedItem class.
 * 
 * @author Aric West
 * @author Daniel Tian
 */
public class TestBorrowedItem {
  private final BorrowedItem item;
  private final String itemName;
  private final String dueDate;
  
  /**
   * Constructor.
   * 
   * @throws Exception Throws on all non-runtime exceptions.
   */
  public TestBorrowedItem() throws Exception {
    this.itemName = "test";
    this.dueDate = "01-02-08";
    this.item = new BorrowedItem(this.itemName, this.dueDate);
  }
  
  /** 
   * Testing equality.
   * 
   * @throws Exception Throws on all non-runtime exceptions.
   */
  @Test
  public void testEquality() throws Exception {
    BorrowedItem item2;
    BorrowedItem item3;
    
    // reflexivity
    item2 = this.item;
    assertTrue("Testing reflexivity (a = a)", this.item.equals(item2));
    
    // symmetry
    item2 = new BorrowedItem(this.itemName, this.dueDate);
    assertEquals("Testing symmetry (a = b) = (b = a)",
      this.item.equals(item2), item2.equals(this.item));
    
    // transitivity
    item3 = new BorrowedItem(this.itemName, this.dueDate);
    assertEquals("Testing transitivity (a = b)", this.item, item2);
    assertEquals("Testing transitivity (b = c)", item2, item3);
    assertEquals("Testing transitivity (a = c)", this.item, item3);
    
    // hash code
    item3 = new BorrowedItem("random", this.dueDate);
    assertEquals("Testing hash code equals", this.item.hashCode(), item2.hashCode());
    assertNotSame("Testing hash code not equals", this.item.hashCode(), item3.hashCode());
  }
  
  /**
   * Testing getting the item name.
   */
  @Test
  public void testGetItemNameMethod() {
    assertEquals("Testing getting item name", this.itemName, item.getItemName());
  }
  
  /**
   * Testing getting the due date as a Calendar object.
   * 
   * @throws Exception Throws on all run-time exceptions.
   */
  @Test
  public void testGetDueDateMethod() throws Exception {
    SimpleDateFormat dateFormat = new SimpleDateFormat("MM-dd-yy", Locale.US);
    Date date = dateFormat.parse(this.dueDate);
    Calendar calendar = Calendar.getInstance();
    calendar.setTime(date);
    
    assertEquals("Testing getting item date", calendar, item.getDueDate());
  }
  
  /**
   * Testing getting the due date as a String object.
   */
  @Test
  public void testGetDueDateToStringMethod() {
    assertEquals("Testing getting item date to string", "01-02-2008", item.getDueDateToString());
  }
  
  /**
   * Test passing a date string that does not contain a valid date. 
   * 
   * @throws Exception Throws when the date field does not contain a valid date.
   */
  @Test(expected = BorrowedItemException.class)
  public void testPassingInvalidDate() throws Exception {
    new BorrowedItem("test", "NotADate");
  }
  
  /**
   * Test passing null values will throw BorrowedItemException.
   * 
   * @throws Exception Throws when the item name or due date is null.
   */
  @Test(expected = BorrowedItemException.class)
  public void testPassingNullValues() throws Exception {
    new BorrowedItem(null, null);
  }
  
  /**
   * Test toString method.
   * 
   */
  @Test
  public void testToStringMethod() {    
    assertEquals("Testing toString method", "Due: 01-02-2008 | test", item.toString());
  }
}
